import aiofiles
import asyncio
from typing import Union
from functools import partial
from aip import AipContentCensor
from common.utils.config import ConfigUtil
from common.utils.urls import UrlUtil


class BaiduCensor:
    """
    https://ai.baidu.com/ai-doc/ANTIPORN/Wk3h6xg56
    """

    @classmethod
    async def client(cls, configs: dict = None):
        """
        构建客户端

        Args:
            configs (dict): 配置参数

        Author:
            zero
        """
        if configs is None:
            configs = await ConfigUtil.get("content_censor", "baidu", {})

        if not configs.get("app_id"):
            raise Exception("百度内容审核: 请在后台配置 app_id")

        if not configs.get("api_key"):
            raise Exception("百度内容审核: 请在后台配置 api_key")

        if not configs.get("secret_key"):
            raise Exception("百度内容审核: 请在后台配置 secret_key")

        return AipContentCensor(
            appId=configs.get("app_id"),
            apiKey=configs.get("api_key"),
            secretKey=configs.get("secret_key")
        )

    @classmethod
    async def text(cls, text: str) -> Union[str, None]:
        """
        文本审核

        Args:
            text (str): 要审核的文本

        Returns:
            str | None: str=不通过原因, None=通过

        Author:
            zero
        """
        if not text:
            return None

        client = await cls.client()

        loop = asyncio.get_event_loop()
        func = partial(client.textCensorUserDefined, text=text)
        result = await loop.run_in_executor(None, func)

        if result.get("error_code"):
            return cls._handle_error(result)

        if result.get("conclusionType") != 1:
            data = result["data"][0]
            words = ",".join(data["hits"][0]["words"])
            messages = data["msg"]
            return f"{messages} - {words}"

        return None

    @classmethod
    async def image(cls, path: str) -> Union[str, None]:
        """
        图片审核

        Args:
            path (str): 要审核的图片地址

        Returns:
            str | None: str=不通过原因, None=通过

        Author:
            zero
        """
        if not path:
            return None

        client = await cls.client()
        loop = asyncio.get_event_loop()
        
        if path.lower().startswith(("https:", "http:")):
            func = partial(client.imageCensorUserDefined, image=path)
            result = await loop.run_in_executor(None, func)
        else:
            async with aiofiles.open(path, mode="rb") as f:
                content = await f.read()
            func = partial(client.imageCensorUserDefined, image=content)
            result = await loop.run_in_executor(None, func)

        if result.get("error_code") == 282804:
            file_path = UrlUtil.to_relative_url(path)
            file_root = UrlUtil.to_root_path(file_path)
            async with aiofiles.open(file_root, mode="rb") as f:
                content = await f.read()
            func = partial(client.imageCensorUserDefined, image=content)
            result = await loop.run_in_executor(None, func)

        if result.get("error_code"):
            return cls._handle_error(result)

        if result.get("conclusionType") != 1:
            return result["data"][0]

        return None

    @classmethod
    def _handle_error(cls, response: dict) -> str:
        """
        处理处理

        Args:
            response (dict): 响应信息

        Returns:
            str

        Author:
            zero
        """
        code = response.get("error_code")
        msg = response.get("error_msg")

        if code == 1:
            return "1: 服务器内部错误，请重试请求 (BaiduCensor)。"
        elif code == 2:
            return "2: 服务暂不可用，请重试请求 (BaiduCensor)。"
        elif code == 3:
            return "3: 调用的API不存在，请检查接口地址是否输入正确 (BaiduCensor)。"
        elif code == 4:
            return "4: 集群超限额，请再次请求，重复出现请提交工单 (BaiduCensor)。"
        elif code == 6:
            return "6: 接口无权限访问，请检查创建的APP应用是否有该接口的使用权限 (BaiduCensor)。"
        elif code == 14:
            return "14: IMA认证失败，请检查ApiKey相关密钥是否正确 (BaiduCensor)。"
        elif code == 17:
            return "17: 每天流量超限额，请您注意控制日调用量，你可以到百度平台升级限额 (BaiduCensor)。"
        elif code == 18:
            return "18: QPS超限额，请您注意控制处理并发量，你可以到百度平台升级QPS限额 (BaiduCensor)。"
        elif code == 19:
            return "19: 请求总量超限额，请确认是否已领取QPS或需提升配额，你可以到百度平台升级QPS限额 (BaiduCensor)。"
        elif code == 216110:
            return "216110: AppID不存在，请检查控制台应用列表中的应用信息 (BaiduCensor)。"
        elif code == 216111:
            return "216111: 非法用户ID，请检查鉴权AK、SK是否正确 (BaiduCensor)。"
        elif code == 216200:
            return "216200: 空的图片，检查请求参数中的图片字段，不能为空 (BaiduCensor)。"
        elif code == 216201:
            return "216201: 图片格式错误，仅支持 PNG、JPG、JPEG、BMP、GIF、WebP、TIFF (BaiduCensor)。"
        elif code == 216202:
            return "216202: 图片大小错误，图像要求不能少于超出4MB 和 4096像素 (BaiduCensor)。"
        elif code == 282800:
            return "282800: 配置ID不存在，检查使用的AppID是否存在，若AppID没有问题，请检查平台策略 (BaiduCensor)。"
        elif code == 282804:
            return "282804: 图片下载失败，请测试图片URL是否可通过公网访问 (BaiduCensor)。"
        elif code == 282874:
            return "282874: 文本审核参数为空，请检查文本审核入参,不能为空 (BaiduCensor)。"
        elif code == 282909:
            return "282909: 文本字符数超限，请检查字符数是否符合要求 (BaiduCensor)。"
        else:
            return f"{code}: {msg} (BaiduCensor)。"
